using Jupiter.Infrastructure;
using Jupiter.Infrastructure.Cache.Interfaces;
using Jupiter.Infrastructure.Domain;
using Jupiter.Infrastructure.Domain.SqlSugar;
using Jupiter.Infrastructure.Domain.SqlSugar.Basic;
using Jupiter.Infrastructure.Exceptions;
using Jupiter.Infrastructure.Permission;
using Jupiter.Infrastructure.Permission.DataPermissions;
using MediatR;
using Microsoft.Extensions.Configuration;
using Wips.AppService.Authorities.Menus.Requests;
using Wips.Domain.Models.Authorities.Model;

namespace Wips.AppService.SqlSugar.Authorities.Menus
{
    /// <summary>
    /// 菜单请求处理程序
    /// </summary>
    public class MenuRequestHandler :
        RequestHandlerBase<Menu>,
        IRequestHandler<CreateMenuRequest, string>,
        IRequestHandler<UpdateMenuRequest, string>,
        IRequestHandler<DeleteMenuRequest, string>,
        IRequestHandler<MenuStatusChangeRequest, string>
    {
        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<string> Handle(CreateMenuRequest request,
            CancellationToken cancellationToken)
        {
            // 封装实体对象
            var entity = new Menu
            {
                Id = ObjectId.GenerateNewStringId(),
                CreatorId = UserId,
                LastUpdatedUserId = UserId!,
                Name = request.Name,
                Sort = request.Sort,
                Icon = request.Icon,
                Status = request.Status,
                Path = request.Path,
                ParentId = request.ParentId,
                IsInside = request.IsInside
            };

            if (request.ParentId != null)
            {
                entity.ParentPath = await GetParentPathAsync(request.ParentId, cancellationToken);
            }

            await RegisterNewAsync(entity, cancellationToken);

            return entity.Id;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<string> Handle(UpdateMenuRequest request,
            CancellationToken cancellationToken)
        {
            if (request.ParentId == request.Id)
            {
                throw new CoreException("不能选择自己作为上级");
            }


            // 封装实体对象
            var entity = await Query()
                .Where(p => p.Id == request.Id)
                .FirstAsync();

            if (entity == null)
            {
                throw new CoreException("找不到记录");
            }

            if (request.ParentId != null)
            {
                entity.ParentPath = await GetParentPathAsync(request.ParentId, cancellationToken);
            }

            entity.ParentId = request.ParentId;
            entity.Name = request.Name;
            entity.Path = request.Path;
            entity.Sort = request.Sort;
            entity.Icon = request.Icon;
            entity.IsInside = request.IsInside;
            entity.LastUpdatedUserId = UserId!;

            // 更新
            RegisterDirty(entity);
            // 提交

            return entity.Id!;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="CoreException"></exception>
        public async Task<string> Handle(DeleteMenuRequest request,
            CancellationToken cancellationToken)
        {
            // 读取数据
            var entity = await Query()
                .Where(p => p.Id == request.Id)
                .FirstOrDefaultAsync(cancellationToken);
            if (entity == null)
            {
                throw new CoreException("找不到要删除的数据");
            }


            // 删除
            RegisterDelete(entity);

            // 提交

            return "";
        }

        /// <summary>
        /// 状态变更
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<string> Handle(MenuStatusChangeRequest request,
            CancellationToken cancellationToken)
        {
            // 读取数据
            var entity = await Query()
                .FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken);

            if (entity == null)
            {
                throw new CoreException("找不到记录");
            }

            // 变更状态
            entity.StatusChange(UserId!);
            // 更新
            RegisterDirty(entity);
            // 提交

            return entity.Id!;
        }

        #region 私有方法

        /// <summary>
        /// 读取ParentPath
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="CoreException"></exception>
        private async Task<string> GetParentPathAsync(string parentId, CancellationToken cancellationToken = default)
        {
            // 读取上级信息
            var parent = await QueryNoTracking()
                .FirstOrDefaultAsync(p => p.Id == parentId, cancellationToken);

            if (parent == null)
            {
                throw new CoreException("找不到上级菜单");
            }

            return string.IsNullOrEmpty(parent.ParentPath)
                ? parentId
                : $"{parent.ParentPath},{parentId}";
        }

        #endregion


        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="securityContextAccessor"></param>
        /// <param name="facadeResolver"></param>
        /// <param name="cacheManager"></param>
        /// <param name="configuration"></param>
        /// <param name="dataPermission"></param>
        public MenuRequestHandler(ISqlSugarClient dbContext, ISecurityContextAccessor securityContextAccessor,
            IFacadeResolver facadeResolver, ICacheManager cacheManager, IConfiguration configuration,
            IDataPermission dataPermission) : base(
            dbContext, securityContextAccessor, facadeResolver, cacheManager, configuration, dataPermission)
        {
        }
    }
}